home *** CD-ROM | disk | FTP | other *** search
- /* pl-prof.c,v 1.14 1995/09/08 14:27:28 jan Exp
-
- Copyright (c) 1990 Jan Wielemaker. All rights reserved.
- See ../LICENCE to find out about your rights.
- jan@swi.psy.uva.nl
-
- Purpose: program profiler
- */
-
- #include "pl-incl.h"
-
- #ifdef O_PROFILE
-
- #ifdef TIME_WITH_SYS_TIME
- #include <sys/time.h>
- #include <time.h>
- #else
- #ifdef HAVE_SYS_TIME_H
- #include <sys/time.h>
- #else
- #include <time.h>
- #endif
- #endif
-
- forwards void profile(int);
-
- struct itimerval value, ovalue; /* itmer controlling structures */
-
- #ifdef HAVE_SIGACTION
- static struct sigaction osigaction;
- #endif
-
- #ifndef SA_NOMASK
- #define SA_NOMASK 0
- #endif
- #ifndef SA_RESTART
- #define SA_RESTART 0
- #endif
-
- static bool
- startProfiler(int how)
- {
- #ifdef HAVE_SIGACTION
- struct sigaction action;
-
- memset((char *) &action, 0, sizeof(action));
- action.sa_handler = profile;
- action.sa_flags = SA_NOMASK|SA_RESTART;
-
- sigaction(SIGPROF, &action, &osigaction);
- #else
- pl_signal(SIGPROF, profile);
- #endif
-
- value.it_interval.tv_sec = 0;
- value.it_interval.tv_usec = 1;
- value.it_value.tv_sec = 0;
- value.it_value.tv_usec = 1;
-
- if (setitimer(ITIMER_PROF, &value, &ovalue) != 0)
- return warning("Failed to start interval timer: %s", OsError());
- LD->statistics.profiling = how;
-
- succeed;
- }
-
- void
- stopItimer(void)
- { value.it_interval.tv_sec = 0;
- value.it_interval.tv_usec = 0;
- value.it_value.tv_sec = 0;
- value.it_value.tv_usec = 0;
-
- if ( LD->statistics.profiling == NO_PROFILING )
- return;
- if (setitimer(ITIMER_PROF, &value, &ovalue) != 0)
- { warning("Failed to stop interval timer: %s", OsError());
- return;
- }
- }
-
- static bool
- stopProfiler()
- { if ( LD->statistics.profiling == NO_PROFILING )
- succeed;
-
- stopItimer();
- LD->statistics.profiling = NO_PROFILING;
- #ifdef HAVE_SIGACTION
- sigaction(SIGPROF, &osigaction, NULL);
- #else
- #ifdef _AIX
- pl_signal(SIGPROF, SIG_IGN);
- #else
- pl_signal(SIGPROF, SIG_DFL);
- #endif
- #endif
-
- succeed;
- }
-
- word
- pl_profile(term_t old, term_t new)
- { int prof = LD->statistics.profiling;
-
- TRY(setInteger(&prof, "profile", old, new));
- if ( prof == LD->statistics.profiling )
- succeed;
- LD->statistics.profiling = prof;
- switch(prof)
- { case NO_PROFILING:
- return stopProfiler();
- case CUMULATIVE_PROFILING:
- case PLAIN_PROFILING:
- if (LD->statistics.profiling != NO_PROFILING)
- { stopProfiler();
- pl_reset_profiler();
- }
- return startProfiler(prof);
- default:
- warning("$profile/2: illegal second argument");
- fail;
- }
- }
-
- word
- pl_profile_count(term_t head, term_t calls, term_t prom)
- { Procedure proc;
- Definition def;
- int pm;
-
- if ( !get_procedure(head, &proc, 0, GP_FIND) )
- return warning("profile_count/3: No such predicate");
-
- def = proc->definition;
- pm = (LD->statistics.profile_ticks == 0 ? 0 :
- ((1000 * def->profile_ticks) /
- LD->statistics.profile_ticks));
-
- if ( PL_unify_integer(calls, def->profile_calls+def->profile_redos) &&
- PL_unify_integer(prom, pm) )
- succeed;
-
- fail;
- }
-
-
- word
- pl_profile_box(term_t head,
- term_t calls, term_t redos,
- term_t exits, term_t fails)
- { Procedure proc;
- Definition def;
-
- if ( !get_procedure(head, &proc, 0, GP_FIND) )
- return warning("profile_box/5: No such predicate");
- def = proc->definition;
-
- if ( PL_unify_integer(calls, def->profile_calls) &&
- PL_unify_integer(redos, def->profile_redos) &&
- PL_unify_integer(exits, def->profile_calls +
- def->profile_redos -
- def->profile_fails) &&
- PL_unify_integer(fails, def->profile_fails) )
- succeed;
-
- fail;
- }
-
-
- word
- pl_reset_profiler(void)
- { Module module;
- Procedure proc;
- Symbol sm, sp;
-
- if (LD->statistics.profiling != NO_PROFILING)
- stopProfiler();
-
- for_table(sm, GD->tables.modules)
- { module = (Module) sm->value;
- for_table(sp, module->procedures)
- { proc = (Procedure) sp->value;
-
- proc->definition->profile_calls = 0;
- proc->definition->profile_redos = 0;
- proc->definition->profile_fails = 0;
- proc->definition->profile_ticks = 0;
- clear(proc->definition, PROFILE_TICKED);
- }
- }
- LD->statistics.profile_ticks = 0;
-
- succeed;
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- This function is responsible for collection the profiling statistics at
- run time. It is called by the UNIX interval timer on each clock tick of
- the machine (every 20 milli seconds). If profiling is plain we just
- increment the profiling tick of the procedure on top of the stack. For
- cumulative profiling we have to scan the entire local stack. As we
- don't want to increment each invokation of recursive functions on the
- stack we maintain a flag on each function. This flag is set the first
- time the function is found on the stack. If is is found set the profile
- counter will not be incremented. We do a second pass over the frames to
- clear the flags again.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- static void
- profile(int sig)
- { register LocalFrame fr = environment_frame;
-
- #if _AIX
- if ( LD->statistics.profiling == NO_PROFILING )
- return;
- #endif
-
- #if !defined(BSD_SIGNALS) && !defined(HAVE_SIGACTION)
- signal(SIGPROF, profile);
- #endif
-
- LD->statistics.profile_ticks++;
-
- if ( gc_status.active )
- { PROCEDURE_garbage_collect0->definition->profile_ticks++;
- return;
- }
-
- if (fr == (LocalFrame) NULL)
- return;
-
- if (LD->statistics.profiling == PLAIN_PROFILING)
- { fr->predicate->profile_ticks++;
- return;
- }
-
- for(; fr; fr = parentFrame(fr) ) /* CUMULATIVE_PROFILING */
- { register Definition def = fr->predicate;
- if ( false(def, PROFILE_TICKED) )
- { set(def, PROFILE_TICKED);
- def->profile_ticks++;
- }
- }
-
- for(fr = environment_frame; fr; fr = parentFrame(fr) )
- clear(fr->predicate, PROFILE_TICKED);
- }
-
- #else /* O_PROFILE */
-
- void
- stopItimer()
- {
- }
-
- word
- pl_profile(term_t old, term_t new)
- { return notImplemented("profile", 2);
- }
-
- word
- pl_profile_count(term_t head, term_t calls, term_t prom)
- { return notImplemented("profile_count", 3);
- }
-
- word
- pl_profile_box(term_t head,
- term_t calls, term_t redos, term_t exits, term_t fails)
- { return notImplemented("profile_box", 3);
- }
-
- word
- pl_reset_profiler()
- { return notImplemented("reset_profile", 0);
- }
-
- #endif /* O_PROFILE */
-